package settings;

import gui.extra.MemoryFolderChooser;
import lib.XML.XMLTranslateBierScene;
import settings.model.*;

import java.io.*;
import java.util.ArrayList;
import java.util.prefs.BackingStoreException;
import java.util.prefs.InvalidPreferencesFormatException;
import java.util.prefs.Preferences;

import lib.logging.Level;
import lib.logging.Logger;
import lib.library.LibraryActionType;
import lib.library.LibraryOtherFileActionType;

public class SettingsControl {

    private Preferences preferences;
    private Settings settings;
    private static final String BACKING_STORE_AVAIL = "BackingStoreAvail";

    public SettingsControl() {
        if (!backingStoreAvailable())
            Logger.instance.error("Unable to store preferences, used debug for reason");
        preferences = Preferences.userRoot();
        settings = new Settings();
        load();
    }
    
    private static boolean backingStoreAvailable() {
        Preferences prefs = Preferences.userRoot().node("");
        try {
            boolean oldValue = prefs.getBoolean(BACKING_STORE_AVAIL, false);
            prefs.putBoolean(BACKING_STORE_AVAIL, !oldValue);
            prefs.flush();
        } catch(BackingStoreException e) {
            Logger.instance.debug(Logger.stack2String(e));
            return false;
        }
        return true;
    }

    public void store() {
    	Logger.instance.log("SettingsControl, store()", Level.TRACE);
    	try {
    		//clean up
			preferences.clear();
			//EpisodeLibrary
	        storeLibrarySerie();
	        //MovieLibrary
	        storeLibraryMovie();
	        //Settings
	        
	        storeDefaultIncomingFolder();

	        storeMappingBierdopjeScene();

	        storeExcludeSettings();

	        storeQualityRuleSettings();

	        storeProxySettings();
	        
	        preferences.putBoolean("OptionsAlwaysConfirm", settings.isOptionsAlwaysConfirm());
	        preferences.putBoolean("OptionsShowExactMatch", settings.isOptionsShowExactMatch());
	        preferences.putBoolean("OptionsShowOnlyFound", settings.isOptionsShowOnlyFound());
	        preferences.putBoolean("OptionsStopOnSearchError", settings.isOptionsStopOnSearchError());
	        preferences.putBoolean("OptionsAutomaticDownloadSelection", settings.isOptionsAutomaticDownloadSelection());
	        preferences.putBoolean("OptionsNoRuleMatchTakeFirst", settings.isOptionsNoRuleMatchTakeFirst());
	        preferences.putBoolean("OptionRecursive", settings.isOptionRecursive());
	        
	        if (MemoryFolderChooser.getInstance().getMemory() != null)
	        	preferences.put("LastOutputDir", MemoryFolderChooser.getInstance().getMemory().getAbsolutePath());
	        
	        storeScreenSettings();
	      
		} catch (BackingStoreException e) {
			Logger.instance.log(Logger.stack2String(e));
		}
		
    }

    private void storeScreenSettings() {
        preferences.putBoolean("ScreenHideEpisode", settings.getScreenSettings().isHideEpisode());
        preferences.putBoolean("ScreenHideFilename", settings.getScreenSettings().isHideFilename());
        preferences.putBoolean("ScreenHideSeason", settings.getScreenSettings().isHideSeason());
        preferences.putBoolean("ScreenHideTitle", settings.getScreenSettings().isHideTitle());
        preferences.putBoolean("ScreenHideType", settings.getScreenSettings().isHideType());
        preferences.putBoolean("ScreenHideWIP", settings.getScreenSettings().isHideWIP());
    }

    private void storeDefaultIncomingFolder(){
    	Logger.instance.log("SettingsControl, storeDefaultIncomingFolder()", Level.TRACE);
    	int last;
        last = 0;
        for (int i = 0; i < settings.getDefaultIncomingFolders().size(); i++) {
        	Logger.instance.log("SettingsControl, storeDefaultIncomingFolder(), storing:"+ settings.getDefaultIncomingFolders().get(i).getAbsolutePath(), Level.TRACE);
        	preferences.put("GeneralDefaultIncomingFolder" + i, settings.getDefaultIncomingFolders().get(i).getAbsolutePath());
        	last++;
        }
        Logger.instance.log("SettingsControl, storeDefaultIncomingFolder(), stored:"+ last + " DefaultIncomingFolders", Level.TRACE);
        preferences.putInt("lastDefaultIncomingFolder", last);
    }
    
    private void storeProxySettings() {
    	Logger.instance.log("SettingsControl, storeProxySettings()", Level.TRACE);
        preferences.putBoolean("generalProxyEnabled", settings.isGeneralProxyEnabled());
        preferences.put("generalProxyHost", settings.getGeneralProxyHost());
        preferences.putInt("generalProxyPort", settings.getGeneralProxyPort());
        updateProxySettings();
    }

    private void storeLibrarySerie() {
    	Logger.instance.log("SettingsControl, storeLibrarySerie()", Level.TRACE);
    	
    	preferences.put("EpisodeLibraryAction", settings.getEpisodeLibrarySettings().getLibraryAction().toString());
    	preferences.putBoolean("EpisodeLibraryUseTVDBNaming", settings.getEpisodeLibrarySettings().isLibraryUseTVDBNaming());
    	preferences.putBoolean("EpisodeLibraryReplaceChars", settings.getEpisodeLibrarySettings().isLibraryReplaceChars());
    	preferences.put("EpisodeLibraryOtherFileAction", settings.getEpisodeLibrarySettings().getLibraryOtherFileAction().toString());
    	
    	if (settings.getEpisodeLibrarySettings().getLibraryFolder() != null)
            preferences.put("EpisodeLibraryFolder", settings.getEpisodeLibrarySettings().getLibraryFolder().getAbsolutePath());
        preferences.put("EpisodeLibraryStructure", settings.getEpisodeLibrarySettings().getLibraryFolderStructure());        
        preferences.putBoolean("EpisodeLibraryRemoveEmptyFolders", settings.getEpisodeLibrarySettings().isLibraryRemoveEmptyFolders());   
        
        preferences.put("EpisodeLibraryFilename", settings.getEpisodeLibrarySettings().getLibraryFilenameStructure());
        preferences.putBoolean("EpisodeLibraryReplaceSpace", settings.getEpisodeLibrarySettings().isLibraryReplaceSpace());
        preferences.put("EpisodeLibraryReplacingSign", settings.getEpisodeLibrarySettings().getLibraryReplacingSign());
        preferences.putBoolean("EpisodeLibraryIncludeLanguageCode", settings.getEpisodeLibrarySettings().isLibraryIncludeLanguageCode());
        preferences.put("EpisodeLibraryDefaultNlText", settings.getEpisodeLibrarySettings().getDefaultNlText());
        preferences.put("EpisodeLibraryDefaultEnText", settings.getEpisodeLibrarySettings().getDefaultEnText());
    }

    private void storeLibraryMovie() {
    	Logger.instance.log("SettingsControl, storeLibraryMovie()", Level.TRACE);
    	
    	preferences.put("MovieLibraryAction", settings.getMovieLibrarySettings().getLibraryAction().toString());
        preferences.putBoolean("MovieLibraryUseTVDBNaming", settings.getMovieLibrarySettings().isLibraryUseTVDBNaming());
        preferences.putBoolean("MovieLibraryReplaceChars", settings.getMovieLibrarySettings().isLibraryReplaceChars());
        preferences.put("MovieLibraryOtherFileAction", settings.getMovieLibrarySettings().getLibraryOtherFileAction().toString());
        
        if (settings.getMovieLibrarySettings().getLibraryFolder() != null)
            preferences.put("MovieLibraryFolder", settings.getMovieLibrarySettings().getLibraryFolder().getAbsolutePath());
        preferences.put("MovieLibraryStructure", settings.getMovieLibrarySettings().getLibraryFolderStructure());        
        preferences.putBoolean("MovieLibraryRemoveEmptyFolders", settings.getMovieLibrarySettings().isLibraryRemoveEmptyFolders());   
        
        preferences.put("MovieLibraryFilename", settings.getMovieLibrarySettings().getLibraryFilenameStructure());
        preferences.putBoolean("MovieLibraryReplaceSpace", settings.getMovieLibrarySettings().isLibraryReplaceSpace());
        preferences.put("MovieLibraryReplacingSign", settings.getMovieLibrarySettings().getLibraryReplacingSign());
        preferences.putBoolean("MovieLibraryIncludeLanguageCode", settings.getMovieLibrarySettings().isLibraryIncludeLanguageCode());
        preferences.put("MovieDefaultNlText", settings.getMovieLibrarySettings().getDefaultNlText());
        preferences.put("MovieDefaultEnText", settings.getMovieLibrarySettings().getDefaultEnText());
    }

    private void storeMappingBierdopjeScene() {
    	Logger.instance.log("SettingsControl, storeMappingBierdopjeScene()", Level.TRACE);
        int last = 0;
        for (int i = 0; i < settings.getMappingList().size(); i++) {
            preferences.put("Dictionary" + i, settings.getMappingList().get(i).getBierdopjeName()
                    + "\\\\" + settings.getMappingList().get(i).getSceneName()
                    + "\\\\" + settings.getMappingList().get(i).getBierdopjeId());
            last++;
        }
        preferences.putInt("lastItemDictionary", last);
    }

    private void storeExcludeSettings() {
    	Logger.instance.log("SettingsControl, storeExcludeSettings()", Level.TRACE);
        int last;
        last = 0;
        for (int i = 0; i < settings.getExcludeList().size(); i++) {
            preferences.put("ExcludeDescription" + i, settings.getExcludeList().get(i).getDescription());
            preferences.put("ExcludeType" + i, settings.getExcludeList().get(i).getType().toString());
            last++;
        }
        preferences.putInt("lastItemExclude", last);
    }

    private void storeQualityRuleSettings() {
    	Logger.instance.log("SettingsControl, storeQualityRuleSettings()", Level.TRACE);
        int last;
        last = 0;
        for (int i = 0; i < settings.getQualityRuleList().size(); i++) {
            preferences.put("Quality" + i, settings.getQualityRuleList().get(i));
            last++;
        }
        preferences.putInt("lastItemQuality", last);
    }

    public void load() {
    	Logger.instance.log("SettingsControl, load()", Level.TRACE);
        //settings
        settings.setLastOutputDir(new File(preferences.get("LastOutputDir", "")));
        settings.setOptionsAlwaysConfirm(preferences.getBoolean("OptionsAlwaysConfirm", false));
        settings.setOptionsShowExactMatch(preferences.getBoolean("OptionsShowExactMatch", false));
        settings.setOptionsShowOnlyFound(preferences.getBoolean("OptionsShowOnlyFound", false));
        settings.setOptionsStopOnSearchError(preferences.getBoolean("OptionsStopOnSearchError", false));
        settings.setOptionsAutomaticDownloadSelection(preferences.getBoolean("OptionsAutomaticDownloadSelection", false));
        settings.setOptionsNoRuleMatchMatchTakeFirst(preferences.getBoolean("OptionsNoRuleMatchTakeFirst", false));
        settings.setOptionRecursive(preferences.getBoolean("OptionRecursive", false));
        //GeneralDefaultIncomingFolders
        loadGeneralDefaultIncomingFolders();
        //Serie
        loadLibrarySerie();
        //movie
        loadLibraryMovie();
        //mapping
        loadMappingBierdopjeScene();
        //exclude settings
        loadExcludeSettings();
        //quality rules
        loadQualityRuleSettings();
        //proxy settings
        loadProxySettings();
        loadScreenSettings();
    }
    
    private void loadGeneralDefaultIncomingFolders(){
    	Logger.instance.log("SettingsControl, loadGeneralDefaultIncomingFolders()", Level.TRACE);
    	if (preferences.get("GeneralDefaultIncomingFolder", "").equals("")){
    		int last;

            last = preferences.getInt("lastDefaultIncomingFolder", 0);

            for (int i = 0; i < last; i++) {
            	settings.getDefaultIncomingFolders().add(new File(preferences.get("GeneralDefaultIncomingFolder" + i, "")));
            }
    	}else{
    		//compatibility 
    		settings.getDefaultIncomingFolders().add(new File(preferences.get("GeneralDefaultIncomingFolder", "")));
    	}
    }

    private void loadProxySettings() {
    	Logger.instance.log("SettingsControl, loadProxySettings()", Level.TRACE);
        settings.setGeneralProxyEnabled(preferences.getBoolean("generalProxyEnabled", false));
        settings.setGeneralProxyHost(preferences.get("generalProxyHost", ""));
        settings.setGeneralProxyPort(preferences.getInt("generalProxyPort", 80));
        updateProxySettings();
    }

    private void loadQualityRuleSettings() {
    	Logger.instance.log("SettingsControl, loadQualityRuleSettings()", Level.TRACE);
        int last;

        last = preferences.getInt("lastItemQuality", 0);

        for (int i = 0; i < last; i++) {
            settings.getQualityRuleList().add(preferences.get("Quality" + i, ""));
        }
    }

    private void loadExcludeSettings() {
    	Logger.instance.log("SettingsControl, loadExcludeSettings()", Level.TRACE);
        int last;

        last = preferences.getInt("lastItemExclude", 0);
        for (int i = 0; i < last; i++) {
            String description = preferences.get("ExcludeDescription" + i, "");
            String type = preferences.get("ExcludeType" + i, "");
            SettingsExcludeItem sei;
            try {
                sei = new SettingsExcludeItem(description, SettingsExcludeType.valueOf(type));
            } catch (Exception e) {
                sei = new SettingsExcludeItem(description, SettingsExcludeType.FOLDER);
            }

            settings.getExcludeList().add(sei);
        }
        Logger.instance.trace("Settings", "loadExcludeSettings", "ExcludeList Size" + settings.getExcludeList().size());
    }

    private void loadMappingBierdopjeScene() {
    	Logger.instance.log("SettingsControl, loadMappingBierdopjeScene()", Level.TRACE);
        int last = preferences.getInt("lastItemDictionary", 0);
        for (int i = 0; i < last; i++) {
            String s = preferences.get("Dictionary" + i, "");
            String[] items = s.split("\\\\");
            if (items.length == 3) {
                MappingBierdopjeScene item = new MappingBierdopjeScene(items[0], items[2], 0);
                settings.getMappingList().add(item);
            }else if(items.length == 5){
            	int bierid = 0;
            	if (items[4].length() != 0){
            		bierid = Integer.parseInt(items[4]);
            	}
            	MappingBierdopjeScene item = new MappingBierdopjeScene(items[0], items[2], bierid);
            	settings.getMappingList().add(item);
            }
        }
    }

    private void loadLibraryMovie() {
    	Logger.instance.log("SettingsControl, loadLibraryMovie()", Level.TRACE);
        LibrarySettings moLibSet = new LibrarySettings();
                
        moLibSet.setLibraryAction(LibraryActionType.fromString(preferences.get("MovieLibraryAction", "")));      
        moLibSet.setLibraryUseTVDBNaming(preferences.getBoolean("MovieLibraryUseTVDBNaming", false));
        moLibSet.setLibraryReplaceChars(preferences.getBoolean("MovieLibraryReplaceChars", false));
        moLibSet.setLibraryOtherFileAction(LibraryOtherFileActionType.fromString(preferences.get("MovieLibraryOtherFileAction", "NOTHING")));
        
        moLibSet.setLibraryFolder(new File(preferences.get("MovieLibraryFolder", "")));
        moLibSet.setLibraryFolderStructure(checkForOldStructure(preferences.get("MovieLibraryStructure", "")));
        moLibSet.setLibraryRemoveEmptyFolders(preferences.getBoolean("MovieLibraryRemoveEmptyFolders", false));
        
        moLibSet.setLibraryFilenameStructure(checkForOldStructure(preferences.get("MovieLibraryFilename", "")));   
        moLibSet.setLibraryReplaceSpace(preferences.getBoolean("MovieLibraryReplaceSpace", false));
        moLibSet.setLibraryReplacingSign(preferences.get("MovieLibraryReplacingSign", ""));
        moLibSet.setLibraryIncludeLanguageCode(preferences.getBoolean("MovieLibraryIncludeLanguageCode", false));
        moLibSet.setDefaultEnText(preferences.get("MovieLibraryDefaultEnText", ""));
        moLibSet.setDefaultNlText(preferences.get("MovieLibraryDefaultNlText", ""));
        settings.setMovieLibrarySettings(moLibSet);
    }

    private void loadLibrarySerie() {
    	Logger.instance.log("SettingsControl, loadLibrarySerie()", Level.TRACE);
        LibrarySettings epLibSet = new LibrarySettings();
        
        epLibSet.setLibraryAction(LibraryActionType.fromString(preferences.get("EpisodeLibraryAction", "")));      
        epLibSet.setLibraryUseTVDBNaming(preferences.getBoolean("EpisodeLibraryUseTVDBNaming", false));
        epLibSet.setLibraryReplaceChars(preferences.getBoolean("EpisodeLibraryReplaceChars", false));
        epLibSet.setLibraryOtherFileAction(LibraryOtherFileActionType.fromString(preferences.get("EpisodeLibraryOtherFileAction", "NOTHING")));
        
        epLibSet.setLibraryFolder(new File(preferences.get("EpisodeLibraryFolder", "")));
        epLibSet.setLibraryFolderStructure(checkForOldStructure(preferences.get("EpisodeLibraryStructure", "")));
        epLibSet.setLibraryRemoveEmptyFolders(preferences.getBoolean("EpisodeLibraryRemoveEmptyFolders", false));
        
        epLibSet.setLibraryFilenameStructure(checkForOldStructure(preferences.get("EpisodeLibraryFilename", "")));   
        epLibSet.setLibraryReplaceSpace(preferences.getBoolean("EpisodeLibraryReplaceSpace", false));
        epLibSet.setLibraryReplacingSign(preferences.get("EpisodeLibraryReplacingSign", ""));
        epLibSet.setLibraryIncludeLanguageCode(preferences.getBoolean("EpisodeLibraryIncludeLanguageCode", false));
        epLibSet.setDefaultEnText(preferences.get("EpisodeLibraryDefaultEnText", ""));
        epLibSet.setDefaultNlText(preferences.get("EpisodeLibraryDefaultNlText", ""));
        settings.setEpisodeLibrarySettings(epLibSet);
    }

    private String checkForOldStructure(String oldStructure) {
        if (oldStructure.equals("Show\\Season")){
            return "%SHOW NAME%%SEPARATOR%Season %S%";
        }else if (oldStructure.equals("Show\\Series")){
            return "%SHOW NAME%%SEPARATOR%Series %S%";
        }else if (oldStructure.equals("\\")){
            return "%SEPARATOR%";
        }else if (oldStructure.equals("Show S00E00.extension")){
            return "%SHOW NAME% S%SS%E%EE%";
        }else if (oldStructure.equals("Show S00E00 Title.extension")){
            return "%SHOW NAME% S%SS%E%EE% %TITLE%";
        }else if (oldStructure.equals("Show 00X00 Title.extension")){
            return "%SHOW NAME% %SS%X%EE% %TITLE%";
        }else if (oldStructure.equals("Show - S00E00.extension")){
            return "%SHOW NAME% - S%SS%E%EE%";
        }else if (oldStructure.equals("Show S00E00 Title Quality.extension")){
            return "%SHOW NAME% S%SS%E%EE% %TITLE% %QUALITY%";
        }else if (oldStructure.equals("Movie (Year)")){
            return "%MOVIE TITLE% (%YEAR%)";
        }else if (oldStructure.equals("Year\\Movie")){
            return "%YEAR%%SEPARATOR%%MOVIE TITLE%";
        }
        return oldStructure;
    }

    public void exportPreferences(File file) throws IOException, BackingStoreException {
    	Logger.instance.log("SettingsControl, exportPreferences(File file)", Level.TRACE);
        store();
        FileOutputStream fos = new FileOutputStream(file);
        preferences.exportSubtree(fos);
    }

    public void importPreferences(File file) throws IOException, InvalidPreferencesFormatException, BackingStoreException {
    	Logger.instance.log("SettingsControl, importPreferences(File file)", Level.TRACE);
        InputStream is = new BufferedInputStream(new FileInputStream(file));
        preferences.clear();
        Preferences.importPreferences(is);
        load();
    }

    public Settings getSettings() {
        return settings;
    }

    public void setSettings(Settings settings) {
        this.settings = settings;
        store();
    }

    public void updateProxySettings(){
         if (settings.isGeneralProxyEnabled()) {
            System.getProperties().put("proxySet", "true");
            System.getProperties().put("proxyHost", settings.getGeneralProxyHost());
            System.getProperties().put("proxyPort", settings.getGeneralProxyPort());
        }else{
             System.getProperties().put("proxySet", "false");
         }
    }

    public void updateMappingFromOnline() throws Throwable {
        ArrayList<MappingBierdopjeScene> onlineList= XMLTranslateBierScene.getOnlineMappingCollection();
        if (settings.getMappingList().size() == 0){
            settings.setMappingList(onlineList);
        }else{
            for (MappingBierdopjeScene onlineItem : onlineList){
                boolean missing = true;
                for (int i = 0; i < settings.getMappingList().size(); i++){
                    MappingBierdopjeScene localItem = settings.getMappingList().get(i);
                    if ((onlineItem.getBierdopjeId() != localItem.getBierdopjeId()
                                && onlineItem.getBierdopjeName().equalsIgnoreCase(localItem.getBierdopjeName())
                                && onlineItem.getSceneName().equalsIgnoreCase(localItem.getSceneName()))){
                        localItem = onlineItem;
                        settings.getMappingList().set(i, onlineItem);
                        missing = false;
                        break;
                    }else if ((onlineItem.getBierdopjeId() == localItem.getBierdopjeId()
                            && onlineItem.getBierdopjeName().equalsIgnoreCase(localItem.getBierdopjeName())
                            && onlineItem.getSceneName().equalsIgnoreCase(localItem.getSceneName()))){
                        missing = false;
                        break;
                    }
                }
                if (missing)
                    settings.getMappingList().add(onlineItem);
            }
        }
    }
    
    public void loadScreenSettings() {
        settings.getScreenSettings().setHideEpisode(preferences.getBoolean("ScreenHideEpisode", true));
        settings.getScreenSettings().setHideFilename(preferences.getBoolean("ScreenHideFilename", false));
        settings.getScreenSettings().setHideSeason(preferences.getBoolean("ScreenHideSeason", true));
        settings.getScreenSettings().setHideTitle(preferences.getBoolean("ScreenHideTitle", true));
        settings.getScreenSettings().setHideType(preferences.getBoolean("ScreenHideType", true));
        settings.getScreenSettings().setHideWIP(preferences.getBoolean("ScreenHideWIP", true));
    }


}
